{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def mark_color_blocks_with_number_2(pil_image,\n",
    "                                  coord_map,\n",
    "                                  target_rgb=(0, 0, 255),\n",
    "                                  tol=10,\n",
    "                                  min_area=100,\n",
    "                                  max_area=10000,\n",
    "                                  outline_color=(255, 0, 0),\n",
    "                                  outline_width=2,\n",
    "                                  text_color=(255, 0, 0),\n",
    "                                  font_size=30,\n",
    "                                  center_dist_thresh=10,\n",
    "                                  font_path=\"DejaVuSans.ttf\"):\n",
    "    \n",
    "    # 原图像尺寸\n",
    "    W, H = pil_image.size\n",
    "\n",
    "    img = np.array(pil_image.convert(\"RGB\"))\n",
    "    lower = np.clip(np.array(target_rgb) - tol, 0, 255).astype(np.uint8)\n",
    "    upper = np.clip(np.array(target_rgb) + tol, 0, 255).astype(np.uint8)\n",
    "    mask = cv2.inRange(img, lower, upper)\n",
    "\n",
    "    num_labels, labels, stats, _ = cv2.connectedComponentsWithStats(mask, connectivity=8)\n",
    "    draw = ImageDraw.Draw(pil_image)\n",
    "\n",
    "    # 预加载固定字号字体\n",
    "    try:\n",
    "        font = ImageFont.truetype(font_path, font_size)\n",
    "    except IOError:\n",
    "        font = ImageFont.load_default()\n",
    "\n",
    "    centers = []           # 存放最终 (idx, lon, lat)\n",
    "    center_pixels = []     # 存放已绘制框的中心像素 (cx, cy)\n",
    "    label_idx = 1\n",
    "\n",
    "    for i in range(1, num_labels):\n",
    "        x, y, w, h, area = stats[i]\n",
    "        if area < min_area or area > max_area:\n",
    "            continue\n",
    "\n",
    "        cx = x + w // 2\n",
    "        cy = y + h // 2\n",
    "\n",
    "        skip = False\n",
    "        for (px, py) in center_pixels:\n",
    "            if np.hypot(cx - px, cy - py) < center_dist_thresh:\n",
    "                skip = True\n",
    "                break\n",
    "        if skip:\n",
    "            continue\n",
    "\n",
    "        # 计算比例坐标\n",
    "        rx1 = float(x / W)\n",
    "        ry1 = float(y / H)\n",
    "        rx2 = float((x + w) / W)\n",
    "        ry2 = float((y + h) / H)\n",
    "\n",
    "        # 绘制矩形框\n",
    "        draw.rectangle([(x, y), (x + w, y + h)],\n",
    "                       outline=outline_color,\n",
    "                       width=outline_width)\n",
    "\n",
    "        text = str(label_idx)\n",
    "        bbox = font.getbbox(text)\n",
    "        text_w = bbox[2] - bbox[0]\n",
    "        text_h = bbox[3] - bbox[1]\n",
    "        text_pos = (cx - text_w // 2, cy - text_h // 2)\n",
    "        draw.text(text_pos, text, fill=text_color, font=font)\n",
    "\n",
    "        lon_str, lat_str = coord_map[cy, cx].split(',')\n",
    "\n",
    "        # 提取地理坐标\n",
    "        lon, lat = float(lon_str), float(lat_str)\n",
    "\n",
    "        # 记录信息到 dict\n",
    "        centers.append({\n",
    "            'index': label_idx,\n",
    "            'center': (lon, lat),\n",
    "            'topleft': (rx1, ry1),\n",
    "            'bottomright': (rx2, ry2)\n",
    "        })\n",
    "\n",
    "        center_pixels.append((cx, cy))\n",
    "\n",
    "        label_idx += 1\n",
    "\n",
    "    return pil_image, centers"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "地图的左上角坐标和右下角坐标 [\"456137.821015,3476327.358884\", \"456461.016667,3475946.946776\"]\n",
      "每个下塌框的序号和中心坐标 [{\"index\": 1, \"center\": [456443.903277, 3476294.575401], \"topleft\": [0.9397321428571429, 0.08154971552424817], \"bottomright\": [0.9537627551020408, 0.09103224058520726]}, {\"index\": 2, \"center\": [456414.212576, 3476179.214656], \"topleft\": [0.8501275510204082, 0.36846383094012464], \"bottomright\": [0.8600127551020408, 0.41018694120834465]}, {\"index\": 3, \"center\": [456264.006495, 3476146.018803], \"topleft\": [0.3832908163265306, 0.468707667298835], \"bottomright\": [0.39732142857142855, 0.4846924952587375]}, {\"index\": 4, \"center\": [456174.006557, 3476122.101294], \"topleft\": [0.10682397959183673, 0.5350853427255486], \"bottomright\": [0.11734693877551021, 0.5440260092115957]}]\n"
     ]
    }
   ],
   "source": [
    "import json\n",
    "\n",
    "print('地图的左上角坐标和右下角坐标', json.dumps([coord_map[0,0], coord_map[-1,-1]]))\n",
    "\n",
    "print('每个下塌框的序号和中心坐标', json.dumps(center_list))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "language_info": {
   "name": "python"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
